﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Smoo.FolderMonitor
{
    public class MonitorEngine
    {
        private MonitorEngineState currentState;
        private Dictionary<FileSystemWatcher, Folder> watchers;

        public delegate void FolderMonitorEventHandler(object sender, FolderMonitorEventArgs e);
        public delegate void FolderMonitorPathNotFoundEventHandler(object sender, EventArgs e);
        public event FolderMonitorEventHandler FolderChangedHandler;
        public event FolderMonitorPathNotFoundEventHandler FolderNotFoundHandler;

        public List<Folder> FoldersToMonitor { get; set; }

        public MonitorEngineState CurrentState 
        {
            get
            {
                return currentState;
            }
        }

        public MonitorEngine(List<Folder> foldersToMonitor)
        {
            this.FoldersToMonitor = foldersToMonitor;
            watchers = foldersToMonitor.ToDictionary(folder => new FileSystemWatcher());
            currentState = MonitorEngineState.Stopped;
        }

        /// <summary>
        /// starts monitoring folders
        /// </summary>
        /// <returns>returns a boolean value indicating if the start was sucessful</returns>
        public bool Start()
        {
            try
            {
                foreach (var item in watchers)
                {
                    try
                    {
                        item.Key.IncludeSubdirectories = true;
                        item.Key.Filter = "*.*";
                        item.Key.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
                        item.Key.Path = item.Value.Path;

                        // watch for these events
                        item.Key.Created += new FileSystemEventHandler(watcher_Changed);
                        item.Key.Deleted += new FileSystemEventHandler(watcher_Changed);

                        // Begin watching the directory.
                        item.Key.EnableRaisingEvents = true;
                    }
                    catch (Exception) // if folder not found
                    {
                        // TODO: this be refactored to check the path first instead of waiting for an exception
                        if (FolderNotFoundHandler != null)
                        {
                            FolderNotFoundHandler(item.Value, null);
                        }
                    }
                }

                currentState = MonitorEngineState.Started;

                return true;
            }
            catch (ArgumentException argumentException) 
            {
                System.Diagnostics.EventLog.WriteEntry("MonitorEngine", argumentException.Message);
                return false;
            }
        }
        
        /// <summary>
        /// stops monitoring folders.
        /// </summary>
        /// <returns>returns a boolean value indicating if the stop was sucessful</returns>
        public bool Stop()
        {
            try
            {
                foreach (var item in watchers)
                {
                    item.Key.Changed -= new FileSystemEventHandler(watcher_Changed);
                    item.Key.Created -= new FileSystemEventHandler(watcher_Changed);
                    item.Key.Deleted -= new FileSystemEventHandler(watcher_Changed);
                }

                currentState = MonitorEngineState.Stopped;

                return true;
            }
            catch (Exception ex)
            {
                System.Diagnostics.EventLog.WriteEntry("MonitorEngine", ex.Message);

                return false;
            }
        }

        private void watcher_Changed(object sender, FileSystemEventArgs e)
        {
            if (FolderChangedHandler != null)
            {
                FileSystemWatcher watcher = (FileSystemWatcher)sender;
                Folder folder = watchers[watcher];

                FolderChangedHandler(sender, new FolderMonitorEventArgs
                {
                    ChangeType = e.ChangeType.ToString(),
                    FileName = e.Name,
                    FriendlyName = folder.FriendlyName,
                    Path = e.FullPath
                });
            }
        }

    }
}
